package com.quanyan.stadium.service.gameLevelScore.impl;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.quanyan.common.Plugin.Page;
import com.quanyan.common.exception.BizException;
import com.quanyan.stadium.constants.GameConstants;
import com.quanyan.stadium.entity.*;
import com.quanyan.stadium.mapper.TbUserFLScoreMapper;
import com.quanyan.stadium.mapper.TbUserFolkToOfficialMapper;
import com.quanyan.stadium.mapper.TbUserOLScoreMapper;
import com.quanyan.stadium.service.gameLevelScore.AbsGameLevelScore;
import com.quanyan.stadium.service.gameLevelScore.utils.GameLScoreUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author xiaoxiao
 * @date 16/4/11-14:42
 *
 * 用户等级分体系
 *
 */

@Service("gameUserLevelScoreServiceImpl")
public class GameUserLevelScoreServiceImpl extends AbsGameLevelScore {

    private final static Logger logger = LoggerFactory.getLogger(GameUserLevelScoreServiceImpl.class);


    @Autowired
    private TbUserFLScoreMapper tbUserFLScoreMapper;

    @Autowired
    private TbUserOLScoreMapper tbUserOLScoreMapper;

    @Autowired
    private TbUserFolkToOfficialMapper tbUserFolkToOfficialMapper;

    @Autowired
    private FLScore flScore;

    @Autowired
    private OLScore olScore;



    /**
     * 用户等级分的统计
     *
     *
     *
     * */

    @Override
    public void collectLScoreIncrement(List<Integer> ownIds, List<Integer> oppIds, String score, Integer gameEventId, Byte categoryId, Integer gameScheduleId) {
        Integer ownId = ownIds.get(0);
        Integer oppId = oppIds.get(0);

        //校验轮空场次
        if ((ownId!=null && ownId>0) && (oppId!=null && oppId>0)) {
            logger.info("当前赛程存在轮空,不计算等级分");
            return;
        }

        Map<String, Object> LScoreParams = new HashMap<>();
        LScoreParams.put("score", score);
        LScoreParams.put("categoryId", categoryId);
        LScoreParams.put("gameEventId", gameEventId);
        LScoreParams.put("gameScheduleId", gameScheduleId);
        String[] str = score.split(":");
        int p = Integer.parseInt(str[0]) - Integer.parseInt(str[1]);
        LScoreParams.put("p", p);
        if (ownId.intValue() == oppId.intValue()) {
            return;
        }
        Object  ownLScoreObject  =  this.getObjectLScore(ownId, categoryId);
        if (ownLScoreObject instanceof TbUserFLScore) { //本方民间
            this.collectFLScoreIncrement(ownId, oppId, (TbUserFLScore) ownLScoreObject, LScoreParams);
        }else if (ownLScoreObject instanceof TbUserOLScore) {   //本方官方
            collectFLScoreIncrementR(ownId, oppId, (TbUserOLScore) ownLScoreObject, LScoreParams);
        }


    }

    /**
     *
     * 双方都计算
     * 主场:非标准等级分
     * 客场:非标准等级分/标准等级分
     **
     *
     *
     * */
    public void collectFLScoreIncrement(Integer ownId, Integer oppId, TbUserFLScore  ownFlScore, Map<String, Object> LScoreParams) {

        if (ownId.intValue() == oppId.intValue()) {
            throw new BizException(null, "主客场为同一人或俱乐部");
        }

        if (null == ownFlScore) {
            this.evalOwnFLScore(ownId, this.DEFAULT_FOLK_SCORE, (Byte)LScoreParams.get("categoryId"));
            ownFlScore = (TbUserFLScore) this.queryLatestFLScore(ownId, (Byte)LScoreParams.get("categoryId"));
        }
        Object  oppLScoreObject = this.getObjectLScore(oppId, (Byte)LScoreParams.get("categoryId"));    //对方等级分对象
        // 对手分要传递

        if (oppLScoreObject instanceof TbUserOLScore) {
            //影响主场的 非标分  + 影响客场的 非标分, 并且为主场记录一条挑战的记录
            collectFLScoreIncrementByLO(ownFlScore, (TbUserOLScore)oppLScoreObject, LScoreParams);
        }else if (oppLScoreObject instanceof TbUserFLScore) {
            //影响主场的 非标分  + 影响客场的 非标分
            collectFLScoreIncrementByLL(ownFlScore, (TbUserFLScore)oppLScoreObject, LScoreParams, FLAG_ALL);
        }
    }

    /**
     *
     * 双方都计算
     * 主场:标准等级分
     * 客场:非标准等级分/标准等级分
     **
     *
     *
     * */
    public void collectFLScoreIncrementR(Integer ownId, Integer oppId, TbUserOLScore  ownFlScore, Map<String, Object> LScoreParams) {

        if (ownId.intValue() == oppId.intValue()) {
            throw new BizException(null, "主客场为同一人或俱乐部");
        }

        if (null == ownFlScore) {
            return;
        }
        Object  oppLScoreObject = this.getObjectLScore(oppId, (Byte)LScoreParams.get("categoryId"));    //对方等级分对象


        if (oppLScoreObject instanceof TbUserOLScore) {
            //影响主场的 标分  + 影响客场的 标分
            this.collectOLScoreIncrement(ownId, oppId, LScoreParams);
        }else if (oppLScoreObject instanceof TbUserFLScore) {
            //影响主场的 非标分  + 影响客场的 非标分, 并且为主场记录一条挑战的记录,  必须要调整比分,反转
            String score = (String) LScoreParams.get("score");
            String[] str = score.split(":");    //取反
            int p = Integer.parseInt(str[1]) - Integer.parseInt(str[0]);
            LScoreParams.put("p", p);
            LScoreParams.put("score", str[1]+":"+str[0]);
            collectFLScoreIncrementByLO((TbUserFLScore) oppLScoreObject, ownFlScore, LScoreParams);
        }
    }




    /**
     * 计算非等级分
     * 主场:非标准等级分
     * 客场:非标准等级分
     *
     * flag: 0 双方 1 主场  2 客场
     *
     *
     * */
    public void collectFLScoreIncrementByLL(TbUserFLScore  ownFlScore, TbUserFLScore oppLScore, Map<String, Object> LScoreParams, Byte flag) {

        if (flag.equals(FLAG_ALL)) {
            //主场
            LScoreParams.put("ownLScore", ownFlScore.getCurrentEffectScore());
            LScoreParams.put("oppLScore", oppLScore.getCurrentEffectScore());
            this.collectFLScoreIncrementByLLDetail(ownFlScore, oppLScore,  LScoreParams);

            //客场
            String score = (String) LScoreParams.get("score");
            String[] str = score.split(":");    //取反
            int p = Integer.parseInt(str[1]) - Integer.parseInt(str[0]);
            LScoreParams.put("p", p);
            LScoreParams.put("score", str[1]+":"+str[0]);
            LScoreParams.put("ownLScore", oppLScore.getCurrentEffectScore());
            LScoreParams.put("oppLScore", ownFlScore.getCurrentEffectScore());
            this.collectFLScoreIncrementByLLDetail(oppLScore, ownFlScore, LScoreParams);

        }else if (flag.equals(FLAG_OWN)) {
            //主场
            LScoreParams.put("ownLScore", ownFlScore.getCurrentEffectScore());
            LScoreParams.put("oppLScore", oppLScore.getCurrentEffectScore());
            this.collectFLScoreIncrementByLLDetail(ownFlScore, oppLScore,  LScoreParams);

        }else if (flag.equals(FLAG_OPP)) {
            //客场
            String score = (String) LScoreParams.get("score");
            String[] str = score.split(":");    //取反
            int p = Integer.parseInt(str[1]) - Integer.parseInt(str[0]);
            LScoreParams.put("p", p);
            LScoreParams.put("score", str[1]+":"+str[0]);
            LScoreParams.put("ownLScore", oppLScore.getCurrentEffectScore());
            LScoreParams.put("oppLScore", ownFlScore.getCurrentEffectScore());
            this.collectFLScoreIncrementByLLDetail(oppLScore,ownFlScore, LScoreParams);
        }
    }


    public void collectFLScoreIncrementByLLDetail(TbUserFLScore  ownFlScore, TbUserFLScore oppLScore, Map<String, Object> LScoreParams){

        TbUserFLScore tbUserFLScore = new TbUserFLScore();
        tbUserFLScore.setCategoryId((Byte) LScoreParams.get("categoryId"));
        double LScoreIncrement = flScore.calculateLScoreInc(LScoreParams);  //当前用户等级分变化值,默认值0.00
        tbUserFLScore.setSelfEvalScore(ownFlScore.getSelfEvalScore());
        tbUserFLScore.setUid(ownFlScore.getUid());
        tbUserFLScore.setDisplayScore(super.finalLScore(ownFlScore.getCurrentEffectScore(), LScoreIncrement, (Byte) LScoreParams.get("categoryId")));
        if (ownFlScore.getDisplayScore() > 0) {
            tbUserFLScore.setDisplayScore(super.finalLScore(ownFlScore.getDisplayScore(), LScoreIncrement, (Byte) LScoreParams.get("categoryId")));
        }
        tbUserFLScore.setStatus(ownFlScore.getStatus());
        tbUserFLScore.setCurrentEffectScore(super.finalLScore(ownFlScore.getCurrentEffectScore(), LScoreIncrement, (Byte) LScoreParams.get("categoryId")));
        tbUserFLScore.setIncrScore(LScoreIncrement);

        Gson gson = new Gson();
        Set<Integer> gameEventIds = gson.fromJson(ownFlScore.getGameEventList(), new TypeToken<Set<Integer>>() {
        }.getType());
        Set<Integer> winOppIds = gson.fromJson(ownFlScore.getWinOpponentUidList(), new TypeToken<Set<Integer>>() {
        }.getType());
        if (null == gameEventIds) {
            gameEventIds = new HashSet<>();
        }
        gameEventIds.add((Integer) LScoreParams.get("gameEventId"));
        if (null == winOppIds) {
            winOppIds = new HashSet<>();
        }
        if (((Integer) LScoreParams.get("p")).intValue() > 0) {
            winOppIds.add(oppLScore.getUid());
        }
        gameEventIds.add((Integer) LScoreParams.get("gameEventId"));
        tbUserFLScore.setGameEventList(gson.toJson(gameEventIds));
        tbUserFLScore.setIsWin(GameLScoreUtils.getGameResult((Integer) LScoreParams.get("p")));
        tbUserFLScore.setOpponentCurrentEffectScore(oppLScore.getCurrentEffectScore());
        tbUserFLScore.setWinOpponentUidList(gson.toJson(winOppIds));
        tbUserFLScore.setOpponentUid(oppLScore.getUid());
        tbUserFLScore.setScore((String) LScoreParams.get("score"));
        tbUserFLScore.setCategoryId((byte)LScoreParams.get("categoryId"));
        tbUserFLScore.setGameScheduleId((Integer) LScoreParams.get("gameScheduleId"));
        //判断赢了 10 个不同对手
        if (winOppIds.size() >= 15) {
            tbUserFLScore.setStatus(GameConstants.IS_DELETE);
        }else {
            tbUserFLScore.setStatus(ownFlScore.getStatus());
        }
        tbUserFLScoreMapper.insertSelective(tbUserFLScore);
    }


    /**
     * 计算非等级分,此时第一点记录标准等级分,第二点记录非标准等级分
     * 主场:非标准等级分
     * 客场:标准等级分
     *
     *
     * */
    public void collectFLScoreIncrementByLO(TbUserFLScore  ownFlScore, TbUserOLScore oppLScore, Map<String, Object> LScoreParams) {

        //非VS非
        this.collectFLScoreIncrementByLL(ownFlScore, (TbUserFLScore)this.queryLatestFLScore(oppLScore.getUid(), (Byte) LScoreParams.get("gameScheduleId")), LScoreParams, FLAG_ALL);

        //非VS标(纪录)

        List<TbUserFolkToOfficial> temp = this.queryLastOOLScore(ownFlScore.getUid());
        TbUserFolkToOfficial folkToOfficial = new TbUserFolkToOfficial();
        folkToOfficial.setGameScheduleId((Integer) LScoreParams.get("gameScheduleId"));
        folkToOfficial.setUid(ownFlScore.getUid());
        folkToOfficial.setCategoryId((byte) LScoreParams.get("categoryId"));
        folkToOfficial.setIsWin(GameLScoreUtils.getGameResult((Integer) LScoreParams.get("p")));
        folkToOfficial.setScore((String) LScoreParams.get("score"));
        folkToOfficial.setOpponentUid(oppLScore.getUid());
        folkToOfficial.setOpponentClubId((-1)*oppLScore.getUid());
        folkToOfficial.setOpponentCurrentEffectScore(oppLScore.getCurrentEffectScore());
        Gson gson = new Gson();
        Set<Integer> diffClubIds = null;
        Set<Integer> diffUids = null;
        Set<Integer> gameEventIds = gson.fromJson(ownFlScore.getGameEventList(), new TypeToken<Set<Integer>>() {
        }.getType());
        if (null != temp && temp.size() > 0) {
            TbUserFolkToOfficial tempT = temp.get(0);
            diffClubIds = gson.fromJson(tempT.getOpponentDiffClubList(), new TypeToken<Set<Integer>>() {
            }.getType());

            diffUids = gson.fromJson(tempT.getOpponentOfficialUidList(), new TypeToken<Set<Integer>>() {
            }.getType());

            folkToOfficial.setOpponentOfficialUidList(gson.toJson(diffUids.add(oppLScore.getUid())));
            folkToOfficial.setOpponentDiffClubList(gson.toJson(diffClubIds.add((-1)*oppLScore.getUid())));
        }
        tbUserFolkToOfficialMapper.insertSelective(folkToOfficial);


        //满足条件标分的谙分转化为明分
        if (diffClubIds.size() >= this.USER_OFFICIAL_SCORE_FACTOR_CLUB_NUM && gameEventIds.size() >= this.USER_OFFICIAL_SCORE_FACTOR_EVENT_NUM-1) {
            List<TbUserFolkToOfficial> winTemp = this.queryLastOOLScoreAndWin(ownFlScore.getUid());
            if (null!=winTemp && winTemp.size()>=this.USER_OFFICIAL_SCORE_FACTOR_USER_NUM) {
                this.initOLScore(ownFlScore.getUid(), calOLScore(ownFlScore.getUid(), (byte) LScoreParams.get("p"), (byte) LScoreParams.get("categoryId")), (Byte) LScoreParams.get("categoryId"));
            }
        }
    }


    /**
     * 双方都计算
     *
     * 主场:标准等级分
     * 客场:标准等级分
     *
     *
     *
     * */
    public void collectOLScoreIncrement(Integer ownId, Integer oppId, Map<String, Object> LScoreParams) {
        if (ownId.intValue() == oppId.intValue()) {
            throw new BizException(null, "主客场为同一人或俱乐部");
        }

        TbUserFLScore  ownFlScore = (TbUserFLScore) this.queryLatestFLScore(ownId, (Byte) LScoreParams.get("categoryId"));
        if (null == ownFlScore) {
            this.evalOwnFLScore(ownId, this.DEFAULT_FOLK_SCORE, (Byte) LScoreParams.get("categoryId"));
            ownFlScore = (TbUserFLScore) this.queryLatestFLScore(ownId, (Byte) LScoreParams.get("categoryId"));
        }
        TbUserFLScore  oppFLScore = (TbUserFLScore)this.getObjectLScore(oppId, (Byte) LScoreParams.get("categoryId"));
        //主场
        LScoreParams.put("ownLScore", ownFlScore.getCurrentEffectScore());
        LScoreParams.put("oppLScore", oppFLScore.getCurrentEffectScore());
        this.collectOLScoreIncrementDetail(ownFlScore, oppFLScore, LScoreParams);

        //客场
        String score = (String) LScoreParams.get("score");
        String[] str = score.split(":");    //取反
        int p = Integer.parseInt(str[1]) - Integer.parseInt(str[0]);
        LScoreParams.put("p", p);
        LScoreParams.put("score", str[1]+":"+str[0]);
        LScoreParams.put("ownLScore", oppFLScore.getCurrentEffectScore());
        LScoreParams.put("oppLScore", ownFlScore.getCurrentEffectScore());
        this.collectFLScoreIncrementByLLDetail(oppFLScore, ownFlScore, LScoreParams);
    }

    public void collectOLScoreIncrementDetail(TbUserFLScore ownFlScore, TbUserFLScore oppFLScore, Map<String, Object> LScoreParams) {

        double LScoreIncrement = olScore.calculateLScoreInc(LScoreParams);  //当前用户等级分变化值
        TbUserOLScore tbUserOLScore = new TbUserOLScore();
        tbUserOLScore.setUid(ownFlScore.getUid());
        tbUserOLScore.setGameScheduleId((Integer) LScoreParams.get("gameScheduleId"));
        tbUserOLScore.setCategoryId((Byte) LScoreParams.get("categoryId"));
        tbUserOLScore.setCurrentEffectScore(super.finalLScore(ownFlScore.getCurrentEffectScore(), LScoreIncrement, (Byte) LScoreParams.get("categoryId")));
        tbUserOLScore.setIncrScore(LScoreIncrement);
        tbUserOLScore.setIsWin(GameLScoreUtils.getGameResult((Integer) LScoreParams.get("p")));
        tbUserOLScore.setOpponentUid(oppFLScore.getUid());
        tbUserOLScore.setOpponentCurrentEffectScore(oppFLScore.getCurrentEffectScore());
        tbUserOLScore.setScore((String) LScoreParams.get("score"));
        tbUserOLScoreMapper.insertSelective(tbUserOLScore);
    }

    /**
     * 查询标准分的暗分赢的列表
     *
     * @param uid 用户uid
     *
     * */
    public List<TbUserFolkToOfficial> queryLastOOLScoreAndWin(int uid){
        TbUserFolkToOfficialExample example = new TbUserFolkToOfficialExample();
        TbUserFolkToOfficialExample.Criteria criteria = example.createCriteria();
        criteria.andUidEqualTo(uid);
        criteria.andIsWinEqualTo(GameConstants.IS_DELETE);
        criteria.andIsDeleteEqualTo(GameConstants.IS_NOT_DELETE);
        example.setOrderByClause("id desc");
        return tbUserFolkToOfficialMapper.selectByExample(example);
    }

    /**
     * 查询标准分的暗分
     *
     * @param uid 用户uid
     *
     * */
    public List<TbUserFolkToOfficial> queryLastOOLScore(int uid){
        TbUserFolkToOfficialExample example = new TbUserFolkToOfficialExample();
        TbUserFolkToOfficialExample.Criteria criteria = example.createCriteria();
        criteria.andUidEqualTo(uid);
        criteria.andIsDeleteEqualTo(GameConstants.IS_NOT_DELETE);
        example.setOrderByClause("id desc");
        return tbUserFolkToOfficialMapper.selectByExample(example);
    }


    /**
     * 计算官方等级分
     *
     * @param uid 用户uid
     * @param p 用户净胜球数目
     *
     * */
    public Double calOLScore(int uid, int p, int categoryId){
        double oLScore = 0.00;
        int uNum = 0;
        TbUserFolkToOfficialExample example = new TbUserFolkToOfficialExample();
        TbUserFolkToOfficialExample.Criteria criteria = example.createCriteria();
        criteria.andUidEqualTo(uid);
        criteria.andCategoryIdEqualTo((byte)categoryId);
        criteria.andIsWinEqualTo(GameLScoreUtils.getGameResult(p));
        List<TbUserFolkToOfficial> userFLScores = tbUserFolkToOfficialMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(userFLScores)) {
            for (TbUserFolkToOfficial userFolkToOfficial : userFLScores) {
                oLScore += userFolkToOfficial.getOpponentCurrentEffectScore();
                uNum += 1;
            }
        }
        if (uNum >= this.USER_OFFICIAL_SCORE_FACTOR_USER_NUM) {
            oLScore = oLScore/(double)uNum;
        }
        return oLScore;

    }

    @Override
    public void initOLScore(Integer ownId, Double lScore, Byte categoryId) {
        TbUserOLScore olScore = new TbUserOLScore();
        olScore.setUid(ownId);
        olScore.setCategoryId(categoryId.byteValue());
        olScore.setCurrentEffectScore(lScore);
        tbUserOLScoreMapper.insertSelective(olScore);
    }

    @Override
    public Object queryLatestFLScore(Integer id, Byte categoryId) {
        TbUserFLScoreExample example = new TbUserFLScoreExample();
        TbUserFLScoreExample.Criteria criteria = example.createCriteria();
        criteria.andUidEqualTo(id);
        criteria.andCategoryIdEqualTo(categoryId.byteValue());
        example.setOrderByClause("id desc");
        example.setPage(new Page(0, 1));
        List<TbUserFLScore> tbUserFLScores = tbUserFLScoreMapper.selectByExample(example);
        if (tbUserFLScores.size()>0) {
            return tbUserFLScores.get(0);
        }
        return null;
    }

    @Override
    public Object queryLatestOLScore(Integer id, Byte categoryId) {
        TbUserOLScoreExample exampleO = new TbUserOLScoreExample();
        TbUserOLScoreExample.Criteria criteriaO =exampleO.createCriteria();
        criteriaO.andUidEqualTo(id);
        criteriaO.andCategoryIdEqualTo(categoryId.byteValue());
        exampleO.setOrderByClause("id desc");
        exampleO.setPage(new Page(0, 1));
        List<TbUserOLScore>  olScores = tbUserOLScoreMapper.selectByExample(exampleO);
        if (olScores.size() == 1) {
            return olScores.get(0);
        }
        return null;
    }

    @Override
    public void evalOwnFLScore(Integer id, Double score, Byte categoryId) {
        TbUserFLScore  ownFlScore = (TbUserFLScore) this.queryLatestFLScore(id, categoryId);
        TbUserFLScore tbUserFLScore = new TbUserFLScore();
        tbUserFLScore.setUid(id);
        tbUserFLScore.setCategoryId(categoryId.byteValue());
        tbUserFLScore.setSelfEvalScore(score);
        tbUserFLScore.setCurrentEffectScore(score);
        if (null != ownFlScore) {
            tbUserFLScore.setGameEventList(ownFlScore.getGameEventList());
            //每次自评都要初始化
            tbUserFLScore.setWinOpponentUidList(null);
        }
        tbUserFLScoreMapper.insertSelective(tbUserFLScore);
        logger.info("用户uid:{}自评成功", id);
    }

    @Override
    public List<Double> querySelfEvalRange(Integer id, Byte categoryId) {
        List<Double> lScoreRange = new ArrayList<>();
        TbUserFLScore flScore = (TbUserFLScore) this.queryLatestFLScore(id, categoryId);
        double max = 11000.00;
        if (categoryId == GameConstants.CATEGORY_ID_TENNIS) {
            max = 6000.00;
        }
        if (null == flScore) {
            lScoreRange.add(1000.00);
            lScoreRange.add(max);
            lScoreRange.add(1.00);
        }else {
            if (flScore.getCurrentEffectScore().doubleValue() > flScore.getSelfEvalScore().doubleValue()) {
                lScoreRange.add(flScore.getCurrentEffectScore());
                lScoreRange.add(max);
            }else if (flScore.getCurrentEffectScore().doubleValue() < flScore.getSelfEvalScore().doubleValue()) {
                lScoreRange.add(1000.00);
                lScoreRange.add(flScore.getCurrentEffectScore());
            }else {
                if (flScore.getIncrScore() <= 0 && flScore.getIncrScore() >= 0) {
                    lScoreRange.add(flScore.getCurrentEffectScore());
                    lScoreRange.add(flScore.getCurrentEffectScore());
                }else {
                    lScoreRange.add(1000.00);
                    lScoreRange.add(max);
                }
            }
            lScoreRange.add(0.00);
        }
        return lScoreRange;
    }

    @Override
    public Object getObjectLScore(Integer id, Byte categoryId) {
        TbUserOLScore  olScore = (TbUserOLScore) this.queryLatestOLScore(id, categoryId);
        if (null != olScore) {
            return olScore;
        }else {
            TbUserFLScore  flScore = (TbUserFLScore) this.queryLatestFLScore(id, categoryId);
            if (null != flScore) {
                return flScore;
            }
        }
        this.evalOwnFLScore(id, 1000.00, categoryId);
        return this.queryLatestFLScore(id, categoryId);
    }
}
